package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearnedSectionCountDto;
import com.tianji.learning.domain.dto.LearningPlanDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.service.ILearningLessonService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课表 服务实现类
 * </p>
 *
 * @author xjs
 */
@Slf4j
@Service
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {

    @Autowired
    private CourseClient courseClient;
    @Autowired
    private CatalogueClient catalogueClient;

    @Override
    public PageDTO<LearningLessonVO> pageQuery(PageQuery query) {
        Long userId = UserContext.getUser();
        // 分页查询learning_lession
        // 分页
        Page<LearningLesson> page = query.toMpPage(query.getSortBy(), query.getIsAsc());
        //条件
        LambdaQueryWrapper<LearningLesson> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LearningLesson::getUserId, userId);
        // 查询
        this.page(page, queryWrapper);
        List<LearningLesson> lessons = page.getRecords();
        if(CollUtil.isEmpty(lessons)){
            return PageDTO.empty(page);
        }
        // feign courseClient-> 根据课程id查询课程信息：name、cover、sections
        List<Long> courseIds = lessons.stream().map(LearningLesson::getCourseId).collect(Collectors.toList());
        List<CourseSimpleInfoDTO> courseList = courseClient.getSimpleInfoList(courseIds);
        if(CollUtil.isEmpty(courseList)){
            log.error("根据课程ids：{}查询不到课程信息", courseIds);
            throw new BizIllegalException("网络异常，请稍后重试");
        }
        // list转map
        Map<Long, CourseSimpleInfoDTO> courseMap = courseList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
        // 填充
        List<LearningLessonVO> voList = new ArrayList<>();
        for (LearningLesson lesson : lessons) {
            LearningLessonVO vo = BeanUtil.copyProperties(lesson, LearningLessonVO.class);
            //CourseSimpleInfoDTO course = getCourse(courseList,lesson.getCourseId());
            CourseSimpleInfoDTO course = courseMap.get(lesson.getCourseId());
            if(course == null){
                log.error("根据课程id：{}查询不到课程信息", courseIds);
                throw new BizIllegalException("网络异常，请稍后重试");
            }
            vo.setCourseName(course.getName());
            vo.setCourseCoverUrl(course.getCoverUrl());
            vo.setSections(course.getSectionNum());
            voList.add(vo);
        }
        //返回
        return PageDTO.of(page, voList);
    }

    private CourseSimpleInfoDTO getCourse(List<CourseSimpleInfoDTO> courseList, Long courseId) {
        Optional<CourseSimpleInfoDTO> any = courseList.stream().filter(c -> Objects.equals(c.getId(), courseId)).findAny();
        if(any.isPresent()){
            return any.get();
        }
        return null;
    }

    @Override
    public LearningLessonVO now() {
        Long userId = UserContext.getUser();
        // 查询最近一次正在学习的课程 leaning_lesson
        // select * from learning_lesson where user_id=#{userId} and status = 1 order by latest_learn_time desc limit 1
        LambdaQueryWrapper<LearningLesson> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LearningLesson::getUserId, userId);
        queryWrapper.eq(LearningLesson::getStatus, LessonStatus.LEARNING.getValue());
        queryWrapper.orderByDesc(LearningLesson::getLatestLearnTime);
        queryWrapper.last(" limit 1");
        LearningLesson lesson = this.getOne(queryWrapper);
        if(lesson == null){
            return null;
        }
        LearningLessonVO vo = BeanUtil.copyProperties(lesson, LearningLessonVO.class);
        // 查询总的课程数量
        // select count(*) from learning_lesson where user_id=#{userId} and status in（0，1，2）
        LambdaQueryWrapper<LearningLesson> countWrapper = new LambdaQueryWrapper<>();
        countWrapper.eq(LearningLesson::getUserId, userId)
                .in(LearningLesson::getStatus, Arrays.asList(LessonStatus.NOT_BEGIN.getValue(), LessonStatus.LEARNING.getValue(), LessonStatus.FINISHED.getValue()));
        int count = this.count(countWrapper);
        vo.setCourseAmount(count);
        // feign： courseClient-》courseName、sections、
        List<CourseSimpleInfoDTO> courseList = courseClient.getSimpleInfoList(Arrays.asList(vo.getCourseId()));
        if(CollUtil.isEmpty(courseList)){
            log.error("根据课程ids：{}查询不到课程信息", vo.getCourseId());
            throw new BizIllegalException("网络异常，请稍后重试");
        }
        CourseSimpleInfoDTO course = courseList.get(0);
        vo.setCourseName(course.getName());
        vo.setSections(course.getSectionNum());
        vo.setCourseCoverUrl(course.getCoverUrl());
        // feign：CatalogueClient-》latestSectionName、latestSectionIndex
        List<CataSimpleInfoDTO> catalogList = catalogueClient.batchQueryCatalogue(Arrays.asList(lesson.getLatestSectionId()));
        if(CollUtil.isEmpty(catalogList)){
            log.error("根据章节ids：{}查询不到章节信息", lesson.getLatestSectionId());
            throw new BizIllegalException("网络异常，请稍后重试");
        }
        CataSimpleInfoDTO catalog = catalogList.get(0);
        vo.setLatestSectionName(catalog.getName());
        vo.setLatestSectionIndex(catalog.getCIndex());
        return vo;
    }

    @Override
    public void removeUserCourses(Long userId, List<Long> courseIds) {
        LambdaQueryWrapper<LearningLesson> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LearningLesson::getUserId, userId);
        queryWrapper.in(LearningLesson::getCourseId, courseIds);
        this.remove(queryWrapper);
    }

    @Override
    public Long queryUserLessonByCourseId(Long userId, Long courseId) {
        LearningLesson one = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .in(LearningLesson::getStatus, Arrays.asList(LessonStatus.NOT_BEGIN.getValue(), LessonStatus.LEARNING.getValue(), LessonStatus.FINISHED.getValue()))
                .one();
        return one == null?null:one.getId();
    }

    @Override
    public LearningLesson getCourseStatus(Long userId, Long courseId) {
        return this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .one();
    }

    @Override
    public Integer countLearningLessonByCourse(Long courseId) {
        return this.lambdaQuery()
                .eq(LearningLesson::getCourseId, courseId)
                .count();
    }

    @Override
    public LearningLesson getByUserIdCourseId(Long userId, Long courseId) {
        return this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .one();
    }

    @Override
    public void plan(LearningPlanDTO dto) {
        Long userId = UserContext.getUser();
        this.lambdaUpdate()
                .set(LearningLesson::getWeekFreq, dto.getFreq())
                .set(LearningLesson::getPlanStatus,PlanStatus.PLAN_RUNNING.getValue())
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, dto.getCourseId())
                .update();
    }

    @Override
    public LearningPlanPageVO getPlans(PageQuery query) {
        Long userId = UserContext.getUser();
        // 分页查询课表，得到我的课
        Page<LearningLesson> page = query.toMpPage("update_time", false);
        LambdaQueryWrapper<LearningLesson> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LearningLesson::getUserId, userId)
                .in(LearningLesson::getStatus, Arrays.asList(LessonStatus.NOT_BEGIN.getValue(), LessonStatus.LEARNING.getValue(), LessonStatus.FINISHED.getValue()));
        this.page(page, queryWrapper);
        List<LearningLesson> lessons = page.getRecords();
        if(CollUtil.isEmpty(lessons)){
            return null;
        }
        // 本周总的实际完成的
        int weekFinished = 0;
        // 本周总的计划完成的
        int totalPlan = 0;
        // feign 查询 课程信息
        List<Long> courseIds = lessons.stream().map(LearningLesson::getCourseId).collect(Collectors.toList());
        List<CourseSimpleInfoDTO> courseList = courseClient.getSimpleInfoList(courseIds);
        if(CollUtil.isEmpty(courseList)){
            log.error("根据课程ids：{}查询不到课程信息", courseIds);
            throw new BizIllegalException("网络异常，请稍后重试");
        }
        Map<Long, CourseSimpleInfoDTO> courseMap = courseList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
        // 查询当前用户本周实际学习的小节数量，统计learning_record
        LocalDate now = LocalDate.now();
        LocalDateTime weekBeginTime = DateUtils.getWeekBeginTime(now);
        LocalDateTime weekEndTime = DateUtils.getWeekEndTime(now);
        List<LearnedSectionCountDto> learnedSections = this.baseMapper.getLearnedSectionsByUserId(userId,weekBeginTime,weekEndTime);
        Map<Long, Integer> learnedSectionCountMap = new HashMap<>();
        if(!CollUtil.isEmpty(learnedSections)){
            learnedSectionCountMap = learnedSections.stream().collect(Collectors.toMap(LearnedSectionCountDto::getCourseId, LearnedSectionCountDto::getCount));
        }
        // 封装返回列表
        List<LearningPlanVO> planList = new ArrayList<>();
        for (LearningLesson lesson : lessons) {
            LearningPlanVO planVo = new LearningPlanVO();
            planVo.setId(lesson.getId());
            planVo.setCourseId(lesson.getCourseId());
            planVo.setWeekFreq(lesson.getWeekFreq());
            planVo.setLearnedSections(lesson.getLearnedSections());
            planVo.setLatestLearnTime(lesson.getLatestLearnTime());
            // courseName， sections -》 feign
            CourseSimpleInfoDTO course = courseMap.get(lesson.getCourseId());
            if(course == null){
                log.error("根据课程id：{}查询不到课程信息", lesson.getCourseId());
                throw new BizIllegalException("网络异常，请稍后重试");
            }
            planVo.setCourseName(course.getName());
            planVo.setSections(course.getSectionNum());
            // weekLearnedSections-》统计learningRecord，条件：userId、开始时间、结束时间
            Integer count = learnedSectionCountMap.get(lesson.getCourseId());
            planVo.setWeekLearnedSections(count==null?0:count);
            planList.add(planVo);
            // 累加
            totalPlan += lesson.getWeekFreq();
            weekFinished += (count==null?0:count) ;
        }
        // 返回
        LearningPlanPageVO vo = new LearningPlanPageVO();
        vo.setWeekFinished(weekFinished);
        vo.setWeekTotalPlan(totalPlan);
        vo.setList(planList);
        vo.setTotal(page.getTotal());
        vo.setPages(page.getPages());
        return vo;
    }
}
